<!-- <template>
  <el-popover v-model:visible="visible" placement="bottom" :width="popWidth">
    <template #reference>
      <el-cascader ref="cascaderRef" @click.stop="onFocus" :placeholder="placeholder" v-model="selectValue"
        :props="cascaderProps" :options="innerData" :show-all-levels="false" @change="onChange" clearable>
        <template #suffix>
          <el-icon class="suffix-icon">
            <arrow-down />
          </el-icon>
        </template>
      </el-cascader>
    </template>
    <div class="poper-wrapper">
      <el-tree ref="treeRef" :data="innerData" default-expand-all show-checkbox :expand-on-click-node="false"
        :current-node-key="currentNodeKey" :check-strictly="true" :node-key="valueKey" @check="onCheck"></el-tree>
    </div>
  </el-popover>
</template>

<script lang="ts" setup>
import { computed, nextTick, onMounted, PropType, ref, unref, watch } from 'vue'

interface TreeNodeData {
  label: string
  value: string | number
  id: string | number
  children?: TreeNodeData[]
  [key: string]: any
}

const props = defineProps({
  modelValue: {
    type: [String, Number],
    default: ''
  },
  data: {
    type: Array as PropType<Array<any>>,
    default: () => []
  },
  placeholder: {
    type: String,
    default: '请选择'
  },
  dataFields: {
    type: Object,
    default: () => ({
      label: 'menuName',
      value: 'parentPath',
      id: 'id',
      children: 'children'
    })
  },
  // 新增：是否使用ID作为选中值
  useIdAsValue: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['update:modelValue', 'nodeClick'])
const treeRef = ref()
const innerData = computed(() => transformData(props.data))
const visible = ref(false)
const cascaderRef = ref()
const popWidth = ref(300)

// 根据 useIdAsValue 决定使用哪个字段作为值
const valueKey = computed(() => (props.useIdAsValue ? 'id' : 'value'))
const currentNodeKey = computed(() => (props.useIdAsValue ? findNodeById(innerData.value, props.modelValue)?.id : props.modelValue))

const selectValue = computed({
  get() {
    if (!props.modelValue) return []
    const path = props.useIdAsValue ? findNodePathById(innerData.value, props.modelValue) : findNodePath(innerData.value, props.modelValue)
    return path.length ? [props.useIdAsValue ? path[path.length - 1].id : props.modelValue] : []
  },
  set(val) {
    const value = val && val.length ? val[val.length - 1] : ''
    emit('update:modelValue', value)
  }
})

const cascaderProps = {
  expandTrigger: 'hover',
  value: computed(() => (props.useIdAsValue ? 'id' : 'value')),
  label: 'label',
  children: 'children',
  checkStrictly: true
}

// 通过ID查找节点
function findNodeById(data: TreeNodeData[], targetId: string | number): TreeNodeData | null {
  for (const node of data) {
    if (node.id === targetId) {
      return node
    }
    if (node.children) {
      const found = findNodeById(node.children, targetId)
      if (found) return found
    }
  }
  return null
}

// 通过ID查找节点路径
function findNodePathById(data: TreeNodeData[], targetId: string | number): TreeNodeData[] {
  for (const node of data) {
    if (node.id === targetId) {
      return [node]
    }
    if (node.children) {
      const path = findNodePathById(node.children, targetId)
      if (path.length) {
        return [node, ...path]
      }
    }
  }
  return []
}

function findNodePath(data: TreeNodeData[], targetValue: string | number): TreeNodeData[] {
  for (const node of data) {
    if (node.value === targetValue) {
      return [node]
    }
    if (node.children) {
      const path = findNodePath(node.children, targetValue)
      if (path.length) {
        return [node, ...path]
      }
    }
  }
  return []
}

function transformData(data: Array<any>): TreeNodeData[] {
  return data.map(item => ({
    label: item[props.dataFields.label],
    value: item[props.dataFields.value],
    id: item[props.dataFields.id],
    rawData: item,
    children: item[props.dataFields.children] ? transformData(item[props.dataFields.children]) : undefined
  }))
}

function onCheck(data: TreeNodeData, { checkedKeys }: any) {
  const prevValue = props.modelValue
  const currentValue = props.useIdAsValue ? data.id : data.value

  // 取消之前选中的节点
  if (prevValue && prevValue !== currentValue) {
    treeRef.value.setChecked(props.useIdAsValue ? findNodeById(innerData.value, prevValue)?.id : prevValue, false)
  }

  visible.value = false
  emit('update:modelValue', currentValue)
  emit('nodeClick', {
    id: data.id,
    parentPath: data.value,
    rawData: data.rawData
  })
}

function onChange(value: any) {
  const newValue = value && value.length ? value[value.length - 1] : ''
  if (newValue) {
    const node = props.useIdAsValue ? findNodeById(innerData.value, newValue) : findNodeInTree(innerData.value, newValue)

    if (node) {
      emit('update:modelValue', props.useIdAsValue ? node.id : node.value)
      emit('nodeClick', {
        id: node.id,
        parentPath: node.value,
        rawData: node.rawData
      })
    }
  } else {
    emit('update:modelValue', '')
    emit('nodeClick', { id: '', parentPath: '', rawData: null })
  }
}

function findNodeInTree(data: TreeNodeData[], value: string | number): TreeNodeData | null {
  for (const node of data) {
    if (node.value === value) {
      return node
    }
    if (node.children) {
      const found = findNodeInTree(node.children, value)
      if (found) return found
    }
  }
  return null
}

function onFocus() {
  visible.value = true
}

onMounted(() => {
  nextTick(() => {
    popWidth.value = unref(cascaderRef).$el.clientWidth
  })
})

watch(
  () => props.modelValue,
  newVal => {
    if (treeRef.value) {
      const allNodes = treeRef.value.getCheckedKeys()
      allNodes.forEach((key: string | number) => {
        treeRef.value.setChecked(key, false)
      })

      if (newVal) {
        const checkValue = props.useIdAsValue ? findNodeById(innerData.value, newVal)?.id : newVal
        if (checkValue) {
          treeRef.value.setChecked(checkValue, true)
        }
      }
    }
  },
  { immediate: true }
)

watch(visible, newVal => {
  if (newVal && treeRef.value && props.modelValue) {
    nextTick(() => {
      const checkValue = props.useIdAsValue ? findNodeById(innerData.value, props.modelValue)?.id : props.modelValue
      if (checkValue) {
        treeRef.value.setChecked(checkValue, true)
      }
    })
  }
})
</script>

<style lang="scss">
.poper-wrapper {
  max-height: 300px;
  overflow: auto;
}

:deep(.el-cascader) {
  width: 100%;

  .el-input {
    .suffix-icon {
      height: inherit;
      display: flex;
      justify-content: center;
      align-items: center;
      width: 25px;
    }
  }

  &:focus {
    .suffix-icon {
      transform: rotate(180deg);
    }
  }
}
</style> -->

<template>
  <el-popover v-model:visible="visible" placement="bottom" :width="popWidth">
    <template #reference>
      <el-cascader
        ref="cascaderRef"
        @click.stop="onFocus"
        :placeholder="placeholder"
        v-model="selectValue"
        :props="cascaderProps"
        :options="innerData"
        :show-all-levels="false"
        @change="onChange"
        clearable
      >
        <template #suffix>
          <el-icon class="suffix-icon">
            <arrow-down />
          </el-icon>
        </template>
      </el-cascader>
    </template>
    <div class="poper-wrapper">
      <el-tree 
        ref="treeRef"
        :data="innerData" 
        default-expand-all 
        show-checkbox
        :expand-on-click-node="false"
        :current-node-key="modelValue"
        :check-strictly="true"
        node-key="value"
        @check="onCheck"
      ></el-tree>
    </div>
  </el-popover>
</template>

<script lang="ts" setup>
import { computed, nextTick, onMounted, PropType, ref, unref, watch } from 'vue'

interface TreeNodeData {
  label: string;
  value: string | number;
  id?: string | number;
  children?: TreeNodeData[];
  [key: string]: any;
}

const props = defineProps({
  modelValue: {
    type: [String, Number],
    default: ''
  },
  data: {
    type: Array as PropType<Array<any>>,
    default: () => []
  },
  placeholder: {
    type: String,
    default: '请选择'
  },
  dataFields: {
    type: Object,
    default: () => ({
      label: 'menuName',
      value: 'parentPath',
      id: 'id',
      children: 'children'
    })
  }
})

// 添加了 nodeClick 事件
const emit = defineEmits(['update:modelValue', 'nodeClick'])
const treeRef = ref()
const innerData = computed(() => transformData(props.data))
const visible = ref(false)
const cascaderRef = ref()
const popWidth = ref(300)

const selectValue = computed({
  get() {
    if (!props.modelValue) return []
    const path = findNodePath(innerData.value, props.modelValue)
    return path.length ? [props.modelValue] : []
  },
  set(val) {
    const value = val && val.length ? val[val.length - 1] : ''
    emit('update:modelValue', value)
  }
})

const cascaderProps = {
  expandTrigger: 'hover',
  value: 'value',
  label: 'label',
  children: 'children',
  checkStrictly: true
}

function findNodePath(data: TreeNodeData[], targetValue: string | number): TreeNodeData[] {
  for (const node of data) {
    if (node.value === targetValue) {
      return [node]
    }
    if (node.children) {
      const path = findNodePath(node.children, targetValue)
      if (path.length) {
        return [node, ...path]
      }
    }
  }
  return []
}

// 修改数据转换函数，保留原始数据的 id
function transformData(data: Array<any>): TreeNodeData[] {
  return data.map(item => ({
    label: item[props.dataFields.label],
    value: item[props.dataFields.value],
    id: item[props.dataFields.id],
    rawData: item, // 保存原始数据
    children: item[props.dataFields.children] ? transformData(item[props.dataFields.children]) : undefined
  }))
}

// 修改复选框事件处理，添加 id 的处理
function onCheck(data: TreeNodeData, { checkedKeys }: any) {
  // 取消之前选中的节点
  if (props.modelValue && props.modelValue !== data.value) {
    treeRef.value.setChecked(props.modelValue, false)
  }
  visible.value = false
  emit('update:modelValue', data.value)
  
  // 触发自定义事件，传递完整的节点信息
  emit('nodeClick', {
    id: data.id,
    parentPath: data.value,
    rawData: data.rawData // 如果需要原始数据
  })
}

function onChange(value: any) {
  const newValue = value && value.length ? value[value.length - 1] : ''
  // 找到对应的节点数据
  if (newValue) {
    const node = findNodeInTree(innerData.value, newValue)
    if (node) {
      emit('update:modelValue', newValue)
      emit('nodeClick', {
        id: node.id,
        parentPath: node.value,
        rawData: node.rawData
      })
    }
  } else {
    emit('update:modelValue', '')
    emit('nodeClick', { id: '', parentPath: '', rawData: null })
  }
}

// 辅助函数：在树中查找节点
function findNodeInTree(data: TreeNodeData[], value: string | number): TreeNodeData | null {
  for (const node of data) {
    if (node.value === value) {
      return node
    }
    if (node.children) {
      const found = findNodeInTree(node.children, value)
      if (found) return found
    }
  }
  return null
}

function onFocus() {
  visible.value = true
}

onMounted(() => {
  nextTick(() => {
    popWidth.value = unref(cascaderRef).$el.clientWidth
  })
})

watch(() => props.modelValue, (newVal) => {
  if (treeRef.value) {
    const allNodes = treeRef.value.getCheckedKeys()
    allNodes.forEach((key: string | number) => {
      treeRef.value.setChecked(key, false)
    })
    
    if (newVal) {
      treeRef.value.setChecked(newVal, true)
    }
  }
}, { immediate: true })

watch(visible, (newVal) => {
  if (newVal && treeRef.value && props.modelValue) {
    nextTick(() => {
      treeRef.value.setChecked(props.modelValue, true)
    })
  }
})
</script>

<style lang="scss">
.poper-wrapper {
  max-height: 300px;
  overflow: auto;
}

:deep(.el-cascader) {
  width: 100%;

  .el-input {
    .suffix-icon {
      height: inherit;
      display: flex;
      justify-content: center;
      align-items: center;
      width: 25px;
    }
  }

  &:focus {
    .suffix-icon {
      transform: rotate(180deg);
    }
  }
}
</style>

<!-- <template>

	<el-popover v-model:visible="visible" placement="bottom" :width="popWidth">
		<template #reference>
			<el-input ref="inputRef" @click.native.stop="onFocus" @blur="onBlur" :placeholder="placeholder" v-model="selectValue" readonly class="input-wrapper">
				<template #suffix>
					<el-icon class="suffx-icon">
						<arrow-down />
					</el-icon>
				</template>
			</el-input>
		</template>
		<div class="poper-wrapper">
			<el-tree :data="innerData" default-expand-all :expand-on-click-node="false" @node-click="onNodeClick"></el-tree>
		</div>
	</el-popover>
</template>

<script lang="ts" setup>
import { computed, nextTick, onMounted, PropType, ref, toRaw, unref, watch } from 'vue'
const props = defineProps({
	value: {
		type: [String, Number],
		default: ''
	},
	data: {
		type: Array as PropType<Array<any>>,
		default: () => []
	},
	placeholder: {
		type: String,
		default: '请选择'
	},
	dataFields: {
		type: Object,
		default: () => ({
			label: 'label',
			value: 'value',
			children: 'children'
		})
	}
})
const emitter = defineEmits(['update:value'])
const innerData = computed(() => transformData(props.data))
const selectValue = computed(() => getLabelByValue(innerData.value))
const visible = ref(false)
const inputRef = ref()
const popWidth = ref(300)
function getLabelByValue(data: Array<TreeDataType>): string {
	if (data && data.length > 0) {
		for (let index = 0; index < data.length; index++) {
			const it = data[index]
			if (it.value === props.value) {
				return it.label
			} else {
				if (it.children && it.children.length > 0) {
					const label = getLabelByValue(it.children)
					if (label) {
						return label
					} else {
						continue
					}
				} else {
					continue
				}
			}
		}
	}
	return ''
}
function transformData(data: Array<any>) {
	const innerData: TreeDataType[] = []
	for (let index = 0; index < data.length; index++) {
		const element = data[index]
		const item: TreeDataType = {
			label: element[props.dataFields.label || 'label'],
			value: element[props.dataFields.value || 'value']
		}
		const tempChildren = element[props.dataFields.children || 'children']
		if (tempChildren && tempChildren.length > 0) {
			item.children = transformData(tempChildren)
		}
		innerData.push(item)
	}
	console.log(innerData ,'innerData')
	return innerData
}
function onNodeClick(key: any, item: any) {
	visible.value = false
	emitter('update:value', key.value)
}
function onFocus() {
	visible.value = true
}
function onBlur() {
	visible.value = false
}
onMounted(() => {
	nextTick(() => {
		popWidth.value = unref(inputRef).$el.clientWidth
	})
})
</script>
<style lang="scss">
.poper-wrapper {
	max-height: 300px;
	overflow: auto;
}
.input-wrapper {
	width: 100%;
	.suffx-icon {
		height: inherit;
		display: flex;
		justify-content: center;
		align-items: center;
		width: 25px;
	}
	&:focus {
		.suffx-icon {
			transform: rotate(180deg);
		}
	}
}
</style> -->
